package ldh.im.fxgui.controller.sub;

import com.jfoenix.controls.JFXDialog;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.property.BooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import ldh.im.ImConfig;
import ldh.im.dto.base.OkResp;
import ldh.im.dto.business.group.GroupAddReq;
import ldh.im.fxbase.dao.ImGroupDao;
import ldh.im.fxbase.data.event.EventBusFactory;
import ldh.im.fxbase.data.event.SessionChange;
import ldh.im.fxbase.data.pojo.ImGroup;
import ldh.im.fxbase.data.pojo.ImGroupUser;
import ldh.im.fxbase.data.pojo.ImSession;
import ldh.im.fxbase.data.pojo.ImUser;
import ldh.im.fxbase.rpc.service.RpcGroupService;
import ldh.im.fxbase.service.ImGroupService;
import ldh.im.fxbase.util.*;
import ldh.im.fxbase.util.ImCacheFactory;
import ldh.im.fxgui.handle.IGroupControl;
import ldh.im.fxgui.util.UiUtil;
import ldh.im.fxgui.util.UserHeadImageUtil;
import ldh.rpc.cache.CacheService;
import org.fxmisc.flowless.Cell;
import org.fxmisc.flowless.VirtualFlow;
import org.kordamp.ikonli.fontawesome.FontAwesome;
import org.kordamp.ikonli.javafx.FontIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

public class AddUserToGroupController implements Initializable {

    private static final Logger LOGGER = LoggerFactory.getLogger(AddUserToGroupController.class);

    @FXML private StackPane userPane;
    @FXML private FlowPane selectUserPane;
    @FXML private ScrollPane selectUserScrollPane;
    @FXML private TextField searchTextField;
    @FXML private TextField groupNameTextField;
    @FXML private TextArea groupDescriptionTextArea;


    private JFXDialog dialog;
    private ObservableList<ImUser> items = FXCollections.observableArrayList();
    private FilteredList<ImUser> filteredData = new FilteredList<>(items, s -> true);
    private SortedList<ImUser> sortedList = new SortedList<>(filteredData, this::userComparator);
    private VirtualFlow<ImUser, ?> userList;

    private Set<ImUser> selectImUsers = new HashSet<>();
    private Map<Long, Pane> selectPaneMap = new HashMap<>();
    private ImSession currentImSession;
    private IGroupControl groupControl;
    private BooleanProperty settingPaneShowProperty;

    private Map<Long, RadioButton> initSelectedUserMap = new HashMap<>();

    private ImGroupService imGroupService = BeanFactory.getInstance().getBean(ImGroupService.class);
    private ImGroupDao imGroupDao = BeanFactory.getInstance().getBean(ImGroupDao.class);

    private RpcGroupService rpcGroupService = RpcUtil.getRpcBootstrap().getRpcConfig().getClientBean(RpcGroupService.class);

    public void setDialog(JFXDialog dialog) {
        this.dialog = dialog;
    }

    public void setIGroupControl(IGroupControl IGroupControl) {
        this.groupControl = IGroupControl;
    }

    public void setSettingPaneShowProperty(BooleanProperty settingPaneShowProperty) {
        this.settingPaneShowProperty = settingPaneShowProperty;
    }

    public void setCurrentImSession(ImSession currentImSession) {
        this.currentImSession = currentImSession;

        List<ImUser> imUsers = ImCacheFactory.getInstance().getAllUsers();
        items.addAll(imUsers);

        if (items.size() > 0) {
            userList.show(0);
        }
        if (currentImSession != null && currentImSession.getImGroup() != null) {
            groupNameTextField.setText(currentImSession.getImGroup().getName());
            groupDescriptionTextArea.setText(currentImSession.getImGroup().getDescription());
            groupNameTextField.setEditable(false);
            groupDescriptionTextArea.setEditable(false);
        } else {
            groupNameTextField.setEditable(true);
            groupDescriptionTextArea.setEditable(true);
        }
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        userList = VirtualFlow.createVertical(sortedList, m->{
            return Cell.wrapNode(createPane(m));
        });
//        VirtualizedScrollPane virtualizedScrollPane = new VirtualizedScrollPane<>(userList);
        userPane.getChildren().add(userList);

        searchTextField.textProperty().addListener((InvalidationListener) l->{
            String filter = searchTextField.getText().trim();
            if(filter == null || filter.length() == 0) {
                filteredData.setPredicate(s -> true);
            } else {
                filteredData.setPredicate(s -> s.getUserName().contains(filter));
            }
        });
    }

    @FXML
    public void close(ActionEvent actionEvent) {
        dialog.close();
    }

    @FXML
    public void saveUsers(ActionEvent actionEvent) {
        if (selectImUsers.size() < 1) {
            DialogUtil.alert("提示", "请选择聊天人员");
            return;
        }
        String description = groupDescriptionTextArea.getText();
        if (description != null && description.length() > 1000) {
            DialogUtil.alert("警告", "内容超长");
            return;
        }

        ThreadPoolUtil.submit(()->{
            ExceptionUtil.catchException(()->{
                CacheService cacheService = RpcUtil.getRpcBootstrap().getRpcConfig().getCacheService();
                String currentUserId = (String) cacheService.getCache(ImConfig.LOGIN_USER_ID);
                if (currentImSession == null || currentImSession.isP2p()) { // p2p聊天群升级成群 或新建群
                    if (currentImSession != null && !currentUserId.equals(currentImSession.getToUserId())) {
                        selectImUsers.add(ImCacheFactory.getInstance().getUser(currentImSession.getToUserId()));
                    }

                    selectImUsers.add(ImCacheFactory.getInstance().getUser(currentUserId));
                    if (selectImUsers.size() <= 2) {
                        FxThreadUtil.runLater(()->{
                            DialogUtil.alert("错误", "必须选择2个以上用户组群");
                        });
                        return null;
                    }
                    ImSession imSession = imGroupService.buildImGroup(currentUserId, selectImUsers);
                    ImGroup group = imSession.getImGroup();
                    String groupName = groupNameTextField.getText().trim();
                    if (StringUtil.isNotBlank(groupName)) {
                        group.setName(groupName);
                    } else {
                        group.setName(createGroupName(selectImUsers.stream().collect(Collectors.toList())));
                    }

                    String groupDesc = groupDescriptionTextArea.getText().trim();
                    if (groupDesc != null) {
                        group.setDescription(groupDesc);
                    }

                    imGroupService.createImGroup(imSession);

                    selectImUsers.clear();

                    FxThreadUtil.runLater(()-> {
                        dialog.close();
                        imSession.getImGroup().setServerId(imSession.getImGroup().getCode());
                        UiUtil.switchMessageSession(imSession);
                    });

                    imGroupService.rpcCreateGroup(imSession);
                } else { // 邀请人进群
                    ImGroup imGroup = imGroupDao.getByUserIdAndId(currentUserId, currentImSession.getGroupCode());
                    boolean isAdded = checkSelectUsers(imGroup, selectImUsers);
                    if (isAdded) {
                        FxThreadUtil.runLater(()->{
                            DialogUtil.alert("警告", "重复邀请用户");
                        });
                        return null;
                    }
                    if (selectImUsers.size() < 1) {
                        FxThreadUtil.runLater(()->{
                            DialogUtil.alert("错误", "必须邀请1个以上用户");
                        });
                        return null;
                    }

                    Set<ImGroupUser> groupUserSet = selectImUsers.stream().map(u-> imGroupService.buildGroupUser(u)).collect(Collectors.toSet());
                    imGroup.setGroupUserSet(groupUserSet);
                    imGroupDao.addUsersToImGroup(imGroup);
                    imGroup = imGroupDao.getByUserIdAndId(UiUtil.getLoginImUser().getUserId(), imGroup.getId());
                    currentImSession.setImGroup(imGroup);
                    ImCacheFactory.getInstance().putImGroup(imGroup.getId(), imGroup);

                    dialog.close();
                    EventBusFactory.getInstance().post(new SessionChange(currentImSession.getId()));
                    FxThreadUtil.runLater(()-> {
                        UiUtil.switchMessageSession(currentImSession);
                        if (groupControl != null) {
                            groupControl.refresh();
                        }
                        items.setAll(groupUserSet.stream().map(gu->gu.getUser()).collect(Collectors.toSet()));
                        if (settingPaneShowProperty != null) {
                            settingPaneShowProperty.setValue(false);
                        }
                    });

                    GroupAddReq groupAddReq = new GroupAddReq();
                    groupAddReq.setGroupName(imGroup.getName());
                    groupAddReq.setGroupDesc(imGroup.getDescription());
                    groupAddReq.setGroupId(imGroup.getServerId());
                    groupAddReq.setUserIdSet(groupUserSet.stream().map(u->u.getUserId()).collect(Collectors.toSet()));

                    selectImUsers.clear();
                    OkResp okResp = rpcGroupService.groupAdd(groupAddReq);
                }
                return null;
            }, "创建群");
        });

    }

    private boolean checkSelectUsers(ImGroup group, Set<ImUser> selectImUsers) {
        Set<String> addedUserIds = group.getGroupUserSet().stream().map(gu->gu.getUserId()).collect(Collectors.toSet());
        return selectImUsers.stream().filter(su->addedUserIds.contains(su.getUserId())).count() > 0;
    }

    private Node createPane(ImUser imUser) {
        LOGGER.info("createPane: {}", imUser.getUserId());

        String userId = UiUtil.getLoginImUser().getUserId();
        HBox hBox = new HBox();
        hBox.getStyleClass().add("user-pane");
        RadioButton selectRadio = new RadioButton();

        ImGroupUser groupUser = new ImGroupUser();
        groupUser.setUser(imUser);
        boolean isSelected = false;
        if (currentImSession != null) {
            ImGroup imGroup = currentImSession.getImGroup();
            if (imGroup != null) {
                groupUser.setGroupId(imGroup.getId());
                Set<ImGroupUser> groupUsers = imGroup.getGroupUserSet();
                if (groupUsers.contains(groupUser)) {
                    isSelected = true;
                    selectRadio.setSelected(true);
                    selectRadio.setDisable(true);

                }
            } else {
                String toUserId = currentImSession.getFromUserId();
                if (toUserId.equals(userId) && currentImSession.getToUserId() != null) {
                    toUserId = currentImSession.getToUserId();
                }
                if (imUser.getUserId().equals(toUserId)) {
                    selectRadio.setSelected(true);
                    selectRadio.setDisable(true);
                    hBox.getStyleClass().add("user-selected");
                }
            }
        }

        if (imUser.getUserId().equals(userId)) {
            isSelected = true;
            selectRadio.setSelected(true);
            selectRadio.setDisable(true);
            hBox.getStyleClass().add("user-selected");
        }

        if (!isSelected) {
            selectRadio.selectedProperty().addListener(l-> selectUser(hBox, imUser, selectRadio));

            hBox.setOnMouseClicked(e->{
                selectRadio.setSelected(!selectRadio.isSelected());
            });
        }

        if (selectImUsers.contains(imUser)) {
            selectRadio.setSelected(true);
            hBox.getStyleClass().add("selected");
        }

        ImageView imageView = new ImageView();
        imageView.setFitHeight(40);
        imageView.setFitWidth(40);
        imageView.setImage(UserHeadImageUtil.getHeadImage(imUser.getHeadImg()));
        Label tipLabel = new Label(imUser.getUserName());
        tipLabel.setTooltip(new Tooltip(imUser.getUserName()));
        hBox.getChildren().addAll(selectRadio, imageView);
        hBox.getChildren().add(tipLabel);

        initSelectedUserMap.put(imUser.getId(), selectRadio);

        return hBox;
    }

    private void selectUser(HBox hBox, ImUser imUser, RadioButton selectRadio) {
        if (selectRadio.isSelected()) {
            if (selectImUsers.contains(imUser)) return;
            hBox.getStyleClass().add("selected");
        } else if(selectImUsers.contains(imUser)){
            Pane pane = selectPaneMap.get(imUser.getId());
            selectUserPane.getChildren().remove(pane);
            selectImUsers.remove(imUser);
            hBox.getStyleClass().remove("selected");
            return;
        }

        ImageView imageView = new ImageView(UserHeadImageUtil.getHeadImage(imUser.getHeadImg()));
        imageView.setFitWidth(50);
        imageView.setFitHeight(50);
        Label label = new Label(imUser.getUserName());
        label.setTooltip(new Tooltip(imUser.getUserName()));
        label.setGraphic(imageView);
        label.setMaxSize(50, 70);
        label.setPrefSize(50, 70);
        label.setContentDisplay(ContentDisplay.TOP);

        StackPane stackPane = new StackPane(label);
        stackPane.setUserData(imUser);
        FontIcon fontIcon = FontIcon.of(FontAwesome.CLOSE);
        fontIcon.setIconColor(Color.LIGHTGRAY);
        stackPane.getChildren().add(fontIcon);
        StackPane.setAlignment(fontIcon, Pos.TOP_RIGHT);

        selectUserPane.getChildren().add(stackPane);
        selectUserScrollPane.setVvalue(1);
        selectImUsers.add(imUser);
        selectPaneMap.put(imUser.getId(), stackPane);

        fontIcon.setOnMouseEntered(e-> fontIcon.setIconColor(Color.GRAY));
        fontIcon.setOnMouseExited(e-> fontIcon.setIconColor(Color.LIGHTGRAY));
        fontIcon.setOnMouseClicked(e->{
            selectRadio.setSelected(false);
        });
    }

    private int userComparator(ImUser imUser1, ImUser imUser2) {
        if (imUser1.getUpdateTime() == null) return -1;
        if (imUser2.getUpdateTime() == null) return 1;
        return imUser1.getUpdateTime().compareTo(imUser2.getUpdateTime());
    }

    private String createGroupName(List<ImUser> selectedUsers) {
        if (selectedUsers.size() < 4) {
            return selectedUsers.stream().map(u->u.getUserName()).collect(Collectors.joining(","));
        }
        return selectedUsers.subList(0,4).stream().map(u->u.getUserName()).collect(Collectors.joining(","));
    }
}
